﻿define(["ecp.utils", "ecp.utils.des", "ecp.wwnetwork"], function(utils, desUtil, wwnetwork) {
	
	//缓存开关到本地的KEY
	var LOCALSTORAGE_APM_ENABLE = "ecp_apm_enable";
	//entrie扩容量
	var ENTRIE_NUMBER = 500;
	
	var nws = null;
	if(wwnetwork) {
	    nws = new wwnetwork();
	}

	function network() {
		/**
		 * 发送数量.
		 */
		try{
			this.counts = 10;
			this.actionStartTime = window.performance.timing.navigationStart;
			this.actionEndTime = (new Date()).getTime();
			this.actionName = "load";	
			this.actionAjaxCount = 0;
			this.observeDomChange = false;
			this.lastDomChangeTime = 0;		
			this.lastClickEvent;
			this.lastClickTime = 0;
			window._ecpUniquekeyArr = [];

			//扩充entries容量
			if(window.performance.clearResourceTimings){
				window.performance.clearResourceTimings();
			} else if(window.performance.webkitClearResourceTimings) {
				window.performance.webkitClearResourceTimings();
			}
			if(window.performance.setResourceTimingBufferSize) {
				window.performance.setResourceTimingBufferSize(ENTRIE_NUMBER);
			} else if(window.performance.webkitSetResourceTimingBufferSize) {
				window.performance.webkitSetResourceTimingBufferSize(ENTRIE_NUMBER);
			}			
			
			var _this = this;			
			
			//监控DOCM变更事件，以获取最后渲染时间作为load或用户操作完成时间
			var observeDOM = (function(){
				var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
					eventListenerSupported = window.addEventListener;

				return function(obj, callback){
					if( MutationObserver ){						
						var obs = new MutationObserver(function(mutations, observer){
							if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
								callback();
						});						
						obs.observe( obj, { childList:true, subtree:true });
					}
					else if( eventListenerSupported ){
						obj.addEventListener('DOMNodeInserted', callback, false);
						obj.addEventListener('DOMNodeRemoved', callback, false);						
					}					
				};
			})();
							
			observeDOM( document.body ,function(){ 					
				if (_this.observeDomChange === true){					
					var currentTime = (new Date()).getTime();
					var timeAfterAjax = currentTime - _this.actionEndTime;
					var timeAfterLastDomChange = currentTime - _this.lastDomChangeTime;
					if(timeAfterAjax > 5000 || timeAfterLastDomChange > 30 ){
						//ajax完成后5秒内触发的dom变更时间或者距离上一次dom变更不超过30毫秒才作为前一事件的处理时间															
						_this.observeDomChange = false;							
					}	
					else{
						_this.actionEndTime = currentTime;		
						_this.lastDomChangeTime = currentTime;						
					}													
				}								
			});		

			//绑定用户操作事件
			var onUserAction = function(e){
				_this.lastClickEvent = window.event || e;
				_this.lastClickTime = (new Date()).getTime();				
			}  	
			if (document.body.addEventListener) {
				document.body.addEventListener('click',onUserAction,false);
				document.body.addEventListener('dblclick',onUserAction,false);							
			} else {
				document.body.attachEvent("onclick", onUserAction);
				document.body.attachEvent("ondblclick", onUserAction);			
			}  
		 }
		 catch(e){
			 if (window.console)
			     window.console.error(e);
		 }		 
	};
	/**
	 * 刷新颜色状态.
	 * @param index 序号
	 * @param speed 速度
	 */
	network.prototype.refreshState = function(index, speed, width) {
		if(sessionStorage) {
			sessionStorage.setItem("NetWorkTestState", index);
			sessionStorage.setItem("NetWorkTestSpeed", speed);
			sessionStorage.setItem("NetWorkTestWidth", width);
		} else {
			utils.setCookie("NetWorkTestState", index);
			utils.setCookie("NetWorkTestSpeed", speed);
			utils.setCookie("NetWorkTestWidth", width);
		}
	}
	/**
	 * 获取令牌.
	 */
	network.prototype.getTokenId = function() {
		var tokenId = this.getQueryString("ecp_token");
        if (!tokenId) {
            tokenId = this.getQueryString("ecpDataContext.tokenId");
            if (!tokenId) {
                tokenId = utils.getCookie("ecp_token");
                if (!tokenId) {
                    tokenId = utils.getCookie("ecpDataContext.tokenId");
                }
            }
        }
        if (!tokenId) {
            tokenId = "Empty_Token";
        }
        return tokenId;
	};
	
	/**
	 * 获取url参数.
	 * @param name 参数名
	 */
	network.prototype.getQueryString = function(name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
        var r = location.search.substr(1).match(reg);
        if (r != null) return unescape(decodeURI(r[2]));
        return null;
	}
	
	/**
	*分析用户操作名称
	*/
	network.prototype.analysisAction = function(apmEnable){		
		//todo 兼容firefox的event对象		
		
		var currentActionName ;
		var timeAfterLastClick = (new Date()).getTime() - this.lastClickTime;
		var currentEvent = window.event;		
		if (!currentEvent && this.lastClickEvent){
			currentEvent = this.lastClickEvent;		
		}
		if (currentEvent && (currentEvent.type.indexOf("click") >= 0 ||  
							 currentEvent.type.indexOf("key") >= 0 || 
							 currentEvent.type.indexOf("mouse") >= 0 							
							 )
		   ){			 
			if (!currentEvent.actionName){				
				currentActionName = currentEvent.type;	
				if (currentEvent.target){					
					var selfCaption = currentEvent.target.title || currentEvent.target.placeholder || currentEvent.target.id || currentEvent.target.innerText  ;
					if (selfCaption != "")
						currentActionName =  currentActionName + "~" + (selfCaption.length>8?selfCaption.substr(0,8):selfCaption); //取元素的显示名称
					else if (currentEvent.target.parentElement)
					{
						//取父元素的显示名称
						var parentCaption = currentEvent.target.parentElement.innerText || currentEvent.target.parentElement.title;
						if (parentCaption != "")
							currentActionName = currentActionName + "~" + (parentCaption.length>8?parentCaption.substr(0,8):parentCaption); 
						else if (currentEvent.target.className){
							//取元素的样式名称
							var className = currentEvent.target.className;
							currentActionName = currentActionName + "~" + (className.length>8?className.substr(0,8):className); 
						}
					}
					else if (currentEvent.pageX && currentEvent.pageY){
						//获取点击位置
						currentActionName = currentActionName + "~" + currentEvent.pageX + "," + currentEvent.pageY	//取点击的位置信息
					}
				}
			}
			else{
				//如果与上次是同一个事件源，则从事件源中获取缓存的操作名称
				currentActionName = currentEvent.actionName;
			}
				
					
			//不同的事件源，或同一事件源发生新的批次
			if (currentActionName != this.actionName || 
				(currentActionName == this.actionName && !currentEvent.actionName )
			   ){					  
				this.cacheActionPerfData(this,apmEnable);			
				this.actionStartTime = (new Date()).getTime();
				this.actionName = currentActionName;			
				this.actionAjaxCount = 0;								
				currentEvent.actionName = currentActionName;				
			}			
	   }
	   this.actionAjaxCount = this.actionAjaxCount + 1;
	   if (this.lastClickTime > 0){
		   this.lastClickEvent = null;
		   this.lastClickTime = 0;		   
	   }		   
	   return {"actionId":this.actionStartTime,"actionName":this.actionName};	   
	}
	
	/**
	*缓存操作性能数据
	*/
	network.prototype.cacheActionPerfData = function(me,apmEnable){		
		if(apmEnable && apmEnable.action)
		   window._apmActionPerfData.push({"id":me.actionStartTime,"name":me.actionName,"duration":(me.actionEndTime - me.actionStartTime),"ajaxTimes":me.actionAjaxCount});	
		if(me.actionName.indexOf("load") >= 0 && !window.timeAtStartLoadPageForUI30){
			//将load的时间作为页面实际加载时间
			window.timeAtStartLoadPageForUI30 = me.actionEndTime - me.actionStartTime;  
			this.actionStartTime = (new Date()).getTime();
		}			
	}
	
	/**
	*缓存页面性能数据
	*/
	network.prototype.cachePagePerfData = function(){		
		if(!window.send_pagetiming_data && window.timeAtStartLoadPageForUI30 ){
			//收集performance.timing数据;						
			var timing = window.performance.timing;
			if (timing && timing.loadEventEnd > 0)
			{							
				window.send_pagetiming_data = {};						
				window.send_pagetiming_data.pageTiming = {							
					datatype : "pageDetail",														
					redirectType : window.performance.navigation.type,
					redirectCount : window.performance.navigation.redirectCount,
					navigationStart : timing.navigationStart,
					unloadEventStart : timing.unloadEventStart,
					unloadEventEnd : timing.unloadEventEnd,
					redirectStart : timing.redirectStart,
					redirectEnd : timing.redirectEnd,
					fetchStart : timing.fetchStart,
					domainLookupStart : timing.domainLookupStart,
					domainLookupEnd : timing.domainLookupEnd,
					connectStart : timing.connectStart,
					connectEnd : timing.connectEnd,
					secureConnectionStart : timing.secureConnectionStart || 0,
					requestStart : timing.requestStart,
					responseStart : timing.responseStart,
					responseEnd : timing.responseEnd,
					domLoading : timing.domLoading,
					domInteractive : timing.domInteractive,
					domContentLoadedEventStart : timing.domContentLoadedEventStart,
					domContentLoadedEventEnd : timing.domContentLoadedEventEnd,
					domComplete : timing.domComplete,
					loadEventStart : timing.loadEventStart,
					loadEventEnd : timing.loadEventEnd,
					asyncScriptTime : window.timeAtStartLoadPageForUI30 || 0
				}
			}
		}
	}
	
	
	/**
	 * 生成参数，并加密再往服务端发送.
	 */
	network.prototype.sendToService = function(sysParams, paramAry, sendnow) {
		var me = this;
	    var pValue = paramAry;
	    if(typeof pValue == "object") {
	    	pValue = JSON.stringify(pValue);
	    }
	    
	    var remoteService = sysParams.webAppRoot+"/ecp/webcore/remoteService";
	    var serviceName ="com.ygsoft.ecp.service.monitor.service.IWebApmContext";
		var methodName = "processWebApmData";
		//
	    var paramData = {"ecp_token": sysParams.tokenId, name: serviceName + "." + methodName, params: pValue}; 
	    //加密url.
	    var signification = desUtil.signData(remoteService, 'POST', paramData);
	    if (signification && signification.encryptedParam) {
	    	paramData = signification.encryptedParam;
	    	for (var i in paramData) {
	        	if (paramData[i]) {
	        		paramData[i] = encodeURIComponent(paramData[i]);
	        	}
	    	}
		}
	    var headers = {};
	    if (signification && signification["AZ"]) {
        	headers["AZ"] = signification["AZ"];
        }
        var cmSign = desUtil.getCmSign();
        if (cmSign) {
        	headers["CM"] = cmSign;
        }
		var uniquekey = Math.uuidCompact();
        headers["ecp_uniquekey"] = uniquekey;
        
        var paramDataStr = "";
	    for(var key in paramData) {
	       	if(paramDataStr.length > 0) {
	       	    paramDataStr += "&";
	       	}
	       	paramDataStr += key + "=" + paramData[key];
	    }
	    //属性		
	    var option = {"ecp_token":paramData.ecp_token,
	    		      "serviceName":paramData.name,
	    		      "webAppRoot":sysParams.webAppRoot,
	    		      "paramData":paramDataStr,
	    		      "headers":headers};        
        if(sendnow !== true) {	        
	        var nwk = window._network_test_object;	        
	        if(nwk != null) {
	    	    nwk.postMessage(option);
	        }
        } else {
        	//直接发送.
        	if(nws != null) {
        	    nws.sendService(option, true);
        	}
        }
	}
	/**
	 * 克隆一个节点数据.
	 */
	network.prototype.clonePerformance = function(uka) {
		var mdata = null;
		var cdata = uka.performanceResourceTiming;
		if(cdata != null && cdata.name.indexOf("processWebApmData") == -1) {
			mdata = {};
			for(var key in cdata) {
				if(typeof cdata[key] !== "function") {
					mdata[key] = cdata[key];
				}					
			}
			mdata.ecp_uniquekey = uka.ecp_uniquekey;
			mdata.name = uka.oriUrl;
			mdata.actionId = uka.actionId;
			mdata.actionName = uka.actionName;
		}
		return mdata;
	}
	/**
	 * 发送performance数据包到服务端.
	 */
	network.prototype.sendPerformance = function(apmEnable,isSendNow) {
		if(Worker != null) {			
			//有请求则处理, 满额发送.

			
			//获取所有资源.
			var jpfm = [];
			if(window._ecpUniquekeyArr) {
				jpfm = window._ecpUniquekeyArr;
			}
			if(jpfm.length >= this.counts || isSendNow != null) {
				var webAppRoot = "/grm";
				if(window.require && window.require.s) {
					var cfg = require.s.contexts["_"].config;
					webAppRoot = cfg.webContextPath;
				}
				var _this = this;
					
				//组成数据包传入
				var jsn = {				
							   "tokenId":this.getTokenId() || -1,
						       "webAppRoot":webAppRoot,						      					      
						       "dataType":"actionDetail",							  		
							   "sessionId":this.getTokenId() || -1,							   
							   "pageUrl":window.location.href//.pathname
						   };
				
				//关闭ajax开关
				if(apmEnable && apmEnable.ajax === true){
					jsn.pfm = jpfm;	
				}
				if(apmEnable && apmEnable.action === true && window._apmActionPerfData && window._apmActionPerfData.length > 0){ 
					jsn.action = window._apmActionPerfData;
				}
				//创建线程
				if(window._network_test_object == null) {
					window._network_test_object = new Worker(webAppRoot + "/ecp/webcore/scripts/ecp.webworker.network.js");
				}			    
				var nwk = window._network_test_object;
				//线程计算结束返回
				nwk.onmessage = function(evt) {
					var rdata = evt.data;
					//回写状态
					if(rdata.type == "result") {
					    _this.refreshState(rdata.NetWorkTestState, rdata.NetWorkTestSpeed, rdata.NetWorkTestWidth);
					} else if(rdata.type == "response") {
				    	var responseText = rdata.responseText;
				    	//回调.
				    	if(typeof callBack == "function") {
				    		callBack(responseText);
				    	}
						if(typeof responseText == "string" && (responseText.indexOf("ajax")>=0 || responseText.indexOf("page")>=0)){
							localStorage && localStorage.setItem(LOCALSTORAGE_APM_ENABLE,responseText);
						}
					} else {
						if(rdata.paramAry.length > 0) {
						    _this.sendToService(jsn, [rdata.paramAry]);
						}
					}
				}

				if(!window.send_pagetiming){
					if(window.send_pagetiming_data){
						//收集performance.timing数据;						
						jsn.pageTiming = window.send_pagetiming_data.pageTiming;						
						window.send_pagetiming = true;
					}
				}
				jsn.navigationStart = window.performance.timing.navigationStart;
				jsn.pageContext = window._apmPageContext || {};
				if(isSendNow == null) {
					//发送线程.
					nwk.postMessage(jsn);
					window._ecpUniquekeyArr = [];
					window._apmActionPerfData = [];
				} else {
					/*
					 * 发送数据包到服务端
					 */
					if(nws != null) {
					    nws.setParams(jsn);					
						var paramsAry = nws.getPerformance();
						if(paramsAry.length > 0) {
						    this.sendToService(jsn, [paramsAry], true);
						}
					}
					window._ecpUniquekeyArr = [];
					window._apmActionPerfData = [];
				}

			} //jpfm
		}//worker
	}
	/**
     * 获取启动ajax开关
     */
	network.prototype.getApmEnable = function(){
		try{	
				var apmEnable = localStorage.getItem(LOCALSTORAGE_APM_ENABLE);
				if(apmEnable == null){
					if(window.require) {
						localStorage && localStorage.setItem(LOCALSTORAGE_APM_ENABLE,"{}");
						require(["ecp.service"],function(ecp){
							try{
								ecp.RemoteService.doGetAsync("com.ygsoft.ecp.service.log.MemoryLogService","getServerVersion",[], function(result) {
									if (result.isSuccess()) {
									        var serverVersion = result.data;
									        if(serverVersion !== "GRIS") {
								    			ecp.RemoteService.doGetAsync("com.ygsoft.ecp.service.monitor.service.IWebApmContext","queryEcpApmParam",[], function(result){
												if (result.isSuccess()) {
													localStorage && localStorage.setItem(LOCALSTORAGE_APM_ENABLE,$.toJSON(result.data));
												}
								    			});								    			
										}
									}
								});
								
							}catch(e){
								localStorage && localStorage.setItem(LOCALSTORAGE_APM_ENABLE,"{}");
								window.console && window.console.error(e);
							}
						});
					} else {
						//2.0的访问
						if($ != null && $.ecp != null) {
							try {
								localStorage && localStorage.setItem(LOCALSTORAGE_APM_ENABLE,"{}");
								$.ecp.remoteService.ajax4Bean("com.ygsoft.ecp.service.log.MemoryLogService.getServerVersion()",{}, 
								    function(resp,textStatus ,jqXHR,errorThrown) {
								    	if(errorThrown){
								    		window.console && window.console.info(jqXHR.responseText);
								    	}else{
								    		if(resp !== "GRIS") {
								    			$.ecp.remoteService.ajax4Bean("com.ygsoft.ecp.service.monitor.service.IWebApmContext.queryEcpApmParam()",{}, 
								    				function(cresp,ctextStatus ,cjqXHR,cerrorThrown) {
								    					if(errorThrown){
								    						window.console && window.console.info(cjqXHR.responseText);
								    					}else{
								    						localStorage && localStorage.setItem(LOCALSTORAGE_APM_ENABLE, cresp);
								    					}
								    				}
								    			);								    			
								    		}
								    		return true;
								    	}	
								    }
                                                                );
						    } catch(e) {
								localStorage && localStorage.setItem(LOCALSTORAGE_APM_ENABLE,"{}");
								window.console && window.console.error(e);
							}
						}
					}
				}else{
					apmEnable = $.parseJSON(apmEnable);
					if(!apmEnable){
						apmEnable = {};
					}
				}
				if(typeof apmEnable == "string") {
					apmEnable = $.parseJSON(apmEnable);
				}				
				return apmEnable;
		}catch(e){
			window.console && window.console.error(e);
		}
	}
	/**
     * 初始化Entries收集
     */
	network.prototype.initEntries = function(headers, keyStr, oriKeyStr){				
		var entry = {};
    	try {
    		var uniquekey = Math.uuidCompact();
            headers["ecp_uniquekey"] = uniquekey;			
            
			var apmEnable = this.getApmEnable();
			if(apmEnable && (apmEnable.page === true || apmEnable.action === true || apmEnable.ajax === true)){
				//获取操作名称				
				var actionInfo = this.analysisAction(apmEnable); 		
				
				//页面数据上报
				if(apmEnable.page === true){					
					this.cachePagePerfData();
				}
				//获取entries起始点
				if(apmEnable.ajax === true){
					//缓存下标
					var entriesLen = window.performance && window.performance.getEntries().length;
					if(entriesLen >= ENTRIE_NUMBER) {
						if(window.performance.clearResourceTimings){
							window.performance.clearResourceTimings();
						} else if(window.performance.webkitClearResourceTimings) {
							window.performance.webkitClearResourceTimings();
						}
						entriesLen = 0;
					}
					entry = {"entriesLen":entriesLen, 
					"uniquekey":uniquekey, 
					"keyStr":keyStr,
					"oriKeyStr":oriKeyStr,
					"startTime":(window.performance.now?window.performance.now():(new Date()).getTime()),
					"actionName":actionInfo.actionName,
					"actionId":actionInfo.actionId
					};
				}		
				if(window._ecpTimingClosedEvents == null) {
					var _this = this;
					//初始化页面上下文及用户操作缓存
					window._apmActionPerfData = [];
					window._apmPageContext = {"sessionId":this.getTokenId(),
							"userName":(localStorage && localStorage.getItem("BSPORTAL_LOGIN_USERNAME")) || "-1",
							"pageId":Math.uuidCompact()};
							
					//绑定beforeunload事件
					window._ecpTimingClosedEvents = function() {													
						 try{
							 //补报剩余性能数据。因平台机制原因会执行两次								 
							 if (!_this.execedBeforeUnloadEvent){								 
								 var apmEnable = _this.getApmEnable();
								 if (apmEnable && apmEnable.page){	
									 //计算页面加载时间									 									
									_this.cacheActionPerfData(_this,apmEnable);																										 
									 _this.cachePagePerfData();									 										
								 }		
								 _this.sendPerformance(apmEnable,true);
								 _this.execedBeforeUnloadEvent = true;									 
							 }							 
						 }
						 catch(e){							 
							if(window.console != null) {
							   window.console.error(e);
							}
						 }
					}            		
					if (window.addEventListener) {
						window.addEventListener('beforeunload',window._ecpTimingClosedEvents,false);
					} else {
						window.attachEvent("onbeforeunload", window._ecpTimingClosedEvents);
					}   								
				}						
			}	
				
		} catch(e){
			if(window.console != null) {
    			window.console.error(e);
    		}			
		}		
		return entry;			
    }
	/**
	 * 缓存对象.
	 */
	network.prototype.cacheEntries = function(pfm, entries, paramData) {
		if(pfm.initiatorType === "xmlhttprequest"){
			//克隆数据包.
			var cpfm = {performanceResourceTiming: pfm, 
                        ecp_uniquekey:entries.uniquekey, 
                        name:entries.keyStr, 
                        paramData:paramData, 
                        oriUrl:entries.oriKeyStr,
						actionName:entries.actionName,
						actionId:entries.actionId};
			
			cpfm = this.clonePerformance(cpfm);
			
			window._ecpUniquekeyArr.push(cpfm);
		}
	}
    /**
     * Entries收集
     */
	network.prototype.storeEntries = function(entries, paramData){    	
    	try {    						    
    		//关闭ajax开关
			var apmEnable = this.getApmEnable();
			if(apmEnable != null && apmEnable.ajax != true && apmEnable.page != true && apmEnable.action != true){
				return;
			}			
			
			//将DOM最后变更时间作为加载过程的最后处理时间					
			if (this.actionName == "load"){
				this.observeDomChange = true;
				this.lastDomChangeTime = 0;
			}
			
    		if(window.performance){
				if(apmEnable && apmEnable.ajax === true){
					var me = this;	
					var now = (window.performance.now?window.performance.now():(new Date()).getTime());					
					var duration = now - entries.startTime;
			
					var keyStr = entries.keyStr;
					var pfms = window.performance.getEntries().slice(entries.entriesLen-1);
					var cacheCur = true;//, pfmAry = [];
					//遍历查找.
					$.each(pfms,function(i,p){
						if(p.initiatorType === "xmlhttprequest") {
							var dname = decodeURIComponent(p.name);
							if( ( p.name.indexOf(keyStr)>=0 || dname.indexOf(keyStr)>=0 ) && p.startTime >= entries.startTime && p.duration <= duration ) {
								//pfmAry.push({"pfm":p, "entries":entries, "paramData":paramData});
								cacheCur = false;
								me.cacheEntries(p, entries, paramData); 
								return false;
							}
						}
					});
					//如果找不到则先缓存起来.
					if(cacheCur === true) {
						if(window._ecpNetworkCache == null) {
							window._ecpNetworkCache = {};
						} else {
							//判断旧的是否可以找到数据.
							for(var url in window._ecpNetworkCache) {
								var pfm = window.performance.getEntriesByName(url);
								if(pfm.length > 0) {
									var p = pfm[0];
									var cp = window._ecpNetworkCache[url];
									//pfmAry.push({"pfm":p, "entries":cp.entries, "paramData":cp.paramData});
									me.cacheEntries(p, cp.entries, cp.paramData); 
									delete window._ecpNetworkCache[url];
								}
							}
						}
						window._ecpNetworkCache[entries.keyStr] = {"entries":entries,"paramData":paramData};
					}
								
					this.sendPerformance(apmEnable);					
            	}			
							
        	}
    	} catch(e) {
    		if(window.console != null) {
    			window.console.error(e);
    		}
    	}
		this.actionEndTime = (new Date()).getTime();			
    }
	
	if(window._network_test == null) {
		window._network_test = new network();
	}
	return window._network_test;
});